/*
 * Copyright (C) Cátedra SAES-UMU 2011 <pedromateo@um.es>
 *
 * Android HCI Extractor is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Android HCI Extractor is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.mmi.android.instrumentation.filters;

import java.util.HashMap;

import org.mmi.android.instrumentation.BaseFilter;
import org.mmi.android.instrumentation.viewproxies.BaseViewProxy;
import org.mmi.facades.BaseMmiFacade;

import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;

/**
 * Instrumentation filter for user mouse and navigation input.
 * 
 * @author pedro mateo (pedromateo@um.es)
 *
 */
public class NavigationInputFilter 
extends BaseFilter
implements OnClickListener,
OnLongClickListener,
OnTouchListener,
OnItemClickListener,
OnItemLongClickListener{

	private static final String TAG = "NavigationInputFilter";

	/**
	 * Constructor
	 */
	public NavigationInputFilter(BaseMmiFacade f){
		super(f);
		//
		p_onClickListeners_ = new HashMap<Integer,OnClickListener>();
		p_onLongClickListeners_ = new HashMap<Integer,OnLongClickListener>();
		p_onTouchListeners_ = new HashMap<Integer,OnTouchListener>();
		p_onItemClickListeners_ = new HashMap<Integer,OnItemClickListener>();
		p_onItemLongClickListeners_ = new HashMap<Integer,OnItemLongClickListener>();
	}

	///
	/// InteractionListener interface implementation
	///

	@Override
	public void onInteractionStart() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onInteractionEnd() {
		// TODO Auto-generated method stub

	}

	///
	/// proxied listeners
	///
	
	/**
	 * All the variables called "p_<listener_name>" are a set of
	 * event listeners suscribed to a concrete event. 
	 * As the filter is installed as a listener into the tracked
	 * view objects, the old existing listeners have to be also
	 * notified about the events. The old existing listeners are
	 * included in these sets. In that way, the filter acts as
	 * a proxy forwarding all the notifications to the corresponding
	 * listeners.
	 */
	HashMap<Integer,OnClickListener> p_onClickListeners_;
	HashMap<Integer,OnLongClickListener> p_onLongClickListeners_;
	HashMap<Integer,OnTouchListener> p_onTouchListeners_;
	HashMap<Integer,OnItemClickListener> p_onItemClickListeners_;
	HashMap<Integer,OnItemLongClickListener> p_onItemLongClickListeners_;

	///
	/// BaseFilter abstract methods implementation
	///
	
	@Override
	public void install(View v)
	{
		try{
			if (v != null)
			{
				///
				/// only in AdapterView
				///
				if (v instanceof AdapterView){

					Log.v(TAG,"AdapterView :: Installing listeners");

					if (BaseViewProxy.getOnItemClickListener(v) != null)
						p_onItemClickListeners_.put(v.getId(),
								BaseViewProxy.getOnItemClickListener(v));
					((AdapterView)v).setOnItemClickListener(this);

					if (BaseViewProxy.getOnItemLongClickListener(v) != null)
						p_onItemLongClickListeners_.put(v.getId(),
								BaseViewProxy.getOnItemLongClickListener(v));
					((AdapterView)v).setOnItemLongClickListener(this);
				}
				///
				/// only in not AdapterView
				///
				else{
					/*if (BaseViewProxy.getOnClickListener(v) != null)
					Log.d(TAG,"HAY LISTENER!!!!!!!!!");*/
					Log.v(TAG,"View :: Installing listeners");

					if (BaseViewProxy.getOnClickListener(v) != null)
						p_onClickListeners_.put(v.getId(),
								BaseViewProxy.getOnClickListener(v));
					//if (BaseViewProxy.getOnClickListener(v) != null)
					//	Log.d(TAG,"HAY LISTENER click!!!!!!!!! ID:" + v.getId());
					v.setOnClickListener(this);
				}

				///
				/// always
				///

				if (BaseViewProxy.getOnLongClickListener(v) != null)
				{
					p_onLongClickListeners_.put(v.getId(),
							BaseViewProxy.getOnLongClickListener(v));
					//Log.d(TAG,"HAY LISTENER longclick !!!!!!!!! ID:" + v.getId());
				}
				v.setOnLongClickListener(this);

				if (BaseViewProxy.getOnTouchListener(v) != null)
				{
					p_onTouchListeners_.put(v.getId(),
							BaseViewProxy.getOnTouchListener(v));
					//Log.d(TAG,"HAY LISTENER touch!!!!!!!!! ID:" + v.getId());
				}
				v.setOnTouchListener(this);

			}
			else{
				Log.w(TAG,"View is NULL");
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	/// //////////////////////////////////////////////////////////
	/// //////////////////////////////////////////////////////////

	/// 
	/// filtering methods
	///

	/**
	 * Handles a click event performed over a concrete view.
	 */
	@Override
	public void onClick (View v)
	{
		Log.d(TAG,"event :: " + "onClick");

		///
		/// do my work
		///

		// it is enough with TOUCH event
		// TODO find for situations in which CLICK is
		// performed but not TOUCH
		//
		//mmim_.click(0);

		///
		/// do the proxyed work
		///

		OnClickListener l = p_onClickListeners_.get(v.getId());
		if (l != null)
			l.onClick(v);
		else
			Log.d(TAG,"p_onClickListener_ :: no pre-listener ID:" + v.getId());
	}

	/**
	 * Handles an itemClick event performed over a concrete view.
	 */
	@Override
	public void onItemClick (AdapterView<?> parent, View v, int position, long id)
	{
		Log.d(TAG,"event :: " + "onItemClick");	

		///
		/// do my work
		///

		mmim_.click(0);

		///
		/// do the proxyed work
		///

		OnItemClickListener l = p_onItemClickListeners_.get(v.getId());
		if (l != null)
			l.onItemClick(parent,v,position,id);
		else
			Log.d(TAG,"p_onItemClickListener_ :: no pre-listener " + v.toString());
	}

	/**
	 * Handles a longItemClick event performed over a concrete view.
	 */
	@Override
	public boolean onItemLongClick (AdapterView<?> parent, View v, int position, long id)
	{
		Log.d(TAG,"event :: " + "onItemLongClick");	

		///
		/// do my work
		///

		mmim_.click(0);

		///
		/// do the proxyed work
		///

		OnItemLongClickListener l = p_onItemLongClickListeners_.get(v.getId());
		if (l != null)
			return l.onItemLongClick(parent,v,position,id);
		else{
			Log.d(TAG,"p_onItemLongClickListener_ :: no pre-listener " + v.toString());
			return false;
		}
	}

	/**
	 * Handles a longClick event performed over a concrete view.
	 */
	@Override
	public boolean onLongClick (View v)
	{
		Log.d(TAG,"event :: " + "onLongClick");	

		///
		/// do my work
		///

		mmim_.click(0);

		///
		/// do the proxyed work
		///

		OnLongClickListener l = p_onLongClickListeners_.get(v.getId());
		if (l != null)
			return l.onLongClick(v);
		else{
			Log.d(TAG,"p_onLongClickListener_ :: no pre-listener " + v.toString());
			return false;
		}
	}



	/**
	 * 
	 */
	final private int SCROLL_MOVES_START = 7;
	private int lastTouch_ = -1;
	private int actionMoves_ = 0;
	
	/**
	 * Handles a touch event performed over a concrete view.
	 */
	@Override
	public boolean onTouch (View v, MotionEvent event)
	{
		Log.d(TAG,"event :: " + "onTouch" + event.getAction());	

		///
		/// do my work
		///

		//ACTION_DOWN 0 (0x00000000)
		//ACTION_MOVE 2 (0x00000002)
		//ACTION_UP 1 (0x00000001)
		//ACTION_SCROLL 8 (0x00000008)
		if (event.getAction() == MotionEvent.ACTION_DOWN){
			lastTouch_ = event.getAction();
			actionMoves_ = 0;
		}
		//
		//
		else if (event.getAction() == MotionEvent.ACTION_UP){
			//if last was ACTION_MOVE -> scroll
			//and actionMoves_ >= SCROLL_MOVES_START
			if (lastTouch_ == MotionEvent.ACTION_MOVE &&
					actionMoves_ > SCROLL_MOVES_START){
				mmim_.scroll(0);
			}
			//if last were only a few ACTION_MOVE
			//if last was ACTION_DOWN -> touch click
			else if (lastTouch_ == MotionEvent.ACTION_MOVE ||
					lastTouch_ == MotionEvent.ACTION_DOWN){
				mmim_.touch(0);
			}

			lastTouch_ = event.getAction();
			actionMoves_ = 0;
		}
		//
		//
		else if (event.getAction() == MotionEvent.ACTION_MOVE){
			lastTouch_ = event.getAction();
			actionMoves_++;
		}
		//
		//
		else{
			lastTouch_ = event.getAction();
			actionMoves_ = 0;
		} 

		///
		/// do the proxyed work
		///

		OnTouchListener l = p_onTouchListeners_.get(v.getId());
		if (l != null)
			return l.onTouch(v,event);
		else{
			Log.d(TAG,"p_onTouchListener_ :: no pre-listener ID:" + v.getId());
			return false;
		}
	}
}
